//
//  GLVideoPlayerView.swift
//  uisliderDel
//
//  Created by quan on 2019/8/13.
//  Copyright © 2019 quan. All rights reserved.
//

import UIKit
import SnapKit
import Alamofire
import Reachability
import RxCocoa
import RxSwift


enum GLVideoPlayerType {
    case live
    case replay
}

class GLVideoPlayerView: UIView {
    var type: GLVideoPlayerType
    var url: URL
    var player: IJKFFMoviePlayerController!
    var gestureActionView: GLVideoGesActionView!
    var activityIndicator: UIActivityIndicatorView!
    var playErrorView: GLVideoPlayerHintView!
    var networkingCheckView: GLVideoPlayerHintView?
    var initialNetworkStatus: Reachability.Connection?
    var isShowingNetworkCheekView: Bool {
        return !(networkingCheckView?.isHidden ?? true)
    }
    
    // block for users
    var backBlock: (()->Void)? {
        didSet {
            gestureActionView.backBlock = backBlock
        }
    }
    var playBlock: (()->Void)? {
        didSet {
            gestureActionView.playBlock = playBlock
        }
    }
    var lockBlock: (()->Void)? {
        didSet {
            gestureActionView.lockBlock = lockBlock
        }
    }
    var unlockBlock: (()->Void)? {
        didSet {
            gestureActionView.unlockBlock = unlockBlock
        }
    }
    var fullScreenBlock: (()->Void)? {
        didSet {
            gestureActionView.fullScreenBlock = fullScreenBlock
        }
    }
    var singleTapBlock: (()->Void)? {
        didSet {
            gestureActionView.singleTapBlock = singleTapBlock
        }
    }
    var toolBarAutoHideBlock: (()->Void)? {
        didSet {
            gestureActionView.toolBarAutoHideBlock = toolBarAutoHideBlock
        }
    }
    
    //
    private var needCheckNeetwork: Bool
    
    private var reachability: Reachability?
    private var disposeBag = DisposeBag()
    
    init(type: GLVideoPlayerType, urlString: String, needCheckNeetwork: Bool = true) {
        self.type = type
        self.needCheckNeetwork = needCheckNeetwork
        self.url = URL(string: urlString) ?? URL(string: GLERRORURL)!
        super.init(frame: .zero)

        // 使用该方式屏蔽网络监测
        self.initialNetworkStatus = GLNetworkTool.shared.status
        self.setupPlayer()
        self.setupOtherViews()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupOtherViews() {
        gestureActionView = GLVideoGesActionView.init(frame: .zero)
        self.addSubview(gestureActionView)
        gestureActionView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
        gestureActionView.delegatePlayer = player
        gestureActionView.type = type
        
        activityIndicator = UIActivityIndicatorView.init(style: .whiteLarge)
        self.addSubview(activityIndicator)
        activityIndicator.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }
        activityIndicator.startAnimating()
        
        if needCheckNeetwork &&
        initialNetworkStatus == Reachability.Connection.cellular &&
        !realUser().runningData.videoNetworkChecked {
            networkingCheckView = GLVideoPlayerHintView.init(title: "正在使用非WIFI网络",buttonTitle: "继续播放", action: { [weak self] in
                realUser().runningData.videoNetworkChecked = true
                self?.networkingCheckView?.isHidden = true
                self?.play()
            })
            self.addSubview(networkingCheckView!)
            networkingCheckView?.snp.makeConstraints { (make) in
                make.left.bottom.right.equalToSuperview()
                make.top.equalToSuperview()
            }
            let networkCheckViewBackButton = UIButton.init(type: .custom)
                        
            networkCheckViewBackButton.setImage(GLVideoPlayerView.gl_image(named: "back_white"), for: .normal)
            networkCheckViewBackButton.setImage(GLVideoPlayerView.gl_image(named: "back_white2"), for: .highlighted)
            networkingCheckView?.addSubview(networkCheckViewBackButton)
            networkCheckViewBackButton.rx.tap.subscribe(onNext: { [weak self] e in
                self?.gestureActionView.backAction()
            }).disposed(by: disposeBag)
            networkCheckViewBackButton.snp.makeConstraints { (make) in
                make.top.equalToSuperview().offset(12)
                make.left.equalToSuperview().offset(5)
                make.width.height.equalTo(40)
            }
            self.startListenNetworkReachability()
        }
        
        /*  暂时屏蔽，因为重新创建player后IJKSDLGLView: setupDisplay not ready bug不能解决
        playErrorView = GLVideoPlayerHintView.init(title: "视频播放出错",buttonTitle: "点击重试", action: { [weak self] in
            self?.retry()
        })
        playErrorView.isHidden = true
        self.addSubview(playErrorView)
        playErrorView.snp.makeConstraints { (make) in
            make.left.bottom.right.equalToSuperview()
            make.top.equalToSuperview().offset(UIApplication.shared.statusBarFrame.height + 44.0)
        }
        */
    }
    
    private func setupPlayer() {
        IJKFFMoviePlayerController.setLogReport(true)
        IJKFFMoviePlayerController.setLogLevel(k_IJK_LOG_DEBUG)
        IJKFFMoviePlayerController.checkIfFFmpegVersionMatch(true)
        
        let options = IJKFFOptions.byDefault()
        options?.setPlayerOptionIntValue(30, forKey: "max-fps")
        options?.setPlayerOptionIntValue(0, forKey: "videotoolbox")
        options?.setPlayerOptionIntValue(30, forKey: "framedrop")
        options?.setFormatOptionIntValue(1, forKey: "reconnect")
        // 第二次添加的设置
        options?.setPlayerOptionIntValue(1, forKey: "flush_packets")
        options?.setPlayerOptionIntValue(500, forKey: "max_cached_duration") // 最大缓存大小是3秒，可以依据自己的需求修改
        options?.setPlayerOptionIntValue(1, forKey: "infbuf")    // 无限读
        options?.setPlayerOptionIntValue(1, forKey: "flush_packets")
//        options?.setPlayerOptionIntValue(1, forKey: "an")       // 静音
        options?.setPlayerOptionIntValue(0, forKey: "packet-buffering")
        options?.setPlayerOptionIntValue(1, forKey: "start-on-prepared")
        options?.setPlayerOptionIntValue(3, forKey: "min-frames")
        // ~~~
        options?.setFormatOptionIntValue(1, forKey: "analyzeduration")
        options?.setFormatOptionIntValue(128, forKey: "probesize")
        options?.setFormatOptionValue("prefer_tcp", forKey: "rtsp_flags")
        
        player = IJKFFMoviePlayerController.init(contentURL: url, with: options)
        player.scalingMode = .fill
        player.shouldAutoplay = false
        
        self.insertSubview(player.view, at: 0)
        self.addSubview(player.view)
        player.view.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
        
        self.installMovieNotificationObservers()
        
    }
    
    private func destoryPlayer() {
        self.removeMovieNotificationObservers()
        if let oldPlayer = player {
            oldPlayer.view.removeFromSuperview()
            oldPlayer.stop()
            oldPlayer.shutdown()
        }
        player = nil
    }
    
    private func startListenNetworkReachability() {
        if let reachability = try? Reachability() {
            self.reachability = reachability
            reachability.whenReachable = { [weak self] r in
                self?.actionForNetworkChanged(status: r.connection)
            }
            reachability.whenUnreachable = { _ in
                self.actionForNetworkChanged(status: Reachability.Connection.unavailable)
            }
            do {
                try reachability.startNotifier()
            } catch {
                GLLog?.debug("Unable to start notifier in playerView")
            }}
    }
    
    private func actionForNetworkChanged(status: Reachability.Connection) {
        guard needCheckNeetwork else {
            return
        }
        
        if isShowingNetworkCheekView && status == .wifi {
            networkingCheckView?.isHidden = true
            self.play()
        }
    }
    
    @objc private func loadStateDidChange(notification: NSNotification) {
        //    MPMovieLoadStateUnknown        = 0,
        //    MPMovieLoadStatePlayable       = 1 << 0,
        //    MPMovieLoadStatePlaythroughOK  = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES
        //    MPMovieLoadStateStalled        = 1 << 2, // Playback will be automatically paused in this state, if started
        if (notification.object as? IJKFFMoviePlayerController) != player {
            return
        }
        
        let loadState = player.loadState
        if ((loadState.rawValue & IJKMPMovieLoadState.playthroughOK.rawValue) != 0) {
            // 缓冲结束，可以播放
            activityIndicator.stopAnimating()
        } else if ((loadState.rawValue & IJKMPMovieLoadState.stalled.rawValue) != 0) {
            // 加载中
            activityIndicator.startAnimating()
        }
        
    }
    
    @objc private func moviePlayBackDidFinish(notification: NSNotification) {
        if (notification.object as? IJKFFMoviePlayerController) != player {
                   return
        }
        
        let info = (notification.userInfo?[IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] as? NSNumber)?.intValue ??  -1
        switch (info) {
        case  IJKMPMovieFinishReason.playbackEnded.rawValue:
            GLLog?.debug("正常播放完成")
        case IJKMPMovieFinishReason.userExited.rawValue:
            GLLog?.debug("用户推出播放")
        case IJKMPMovieFinishReason.playbackError.rawValue:
            GLLog?.debug("视频播放错误")
            /*
            activityIndicator.stopAnimating()
            playErrorView.isHidden = false
            */
        default:
            break
        }
    }
    
    @objc private func mediaIsPreparedToPlayDidChange(notification: NSNotification) {
        
    }
    
    @objc private func moviePlayBackStateDidChange(notification: NSNotification) {
        //    MPMoviePlaybackStateStopped,
        //    MPMoviePlaybackStatePlaying,
        //    MPMoviePlaybackStatePaused,
        //    MPMoviePlaybackStateInterrupted,
        //    MPMoviePlaybackStateSeekingForward,
        //    MPMoviePlaybackStateSeekingBackward
        if (notification.object as? IJKFFMoviePlayerController) != player {
            return
        }
        
        switch player.playbackState {
        case .stopped:
            GLLog?.debug("IJKMPMoviePlayBackStateDidChange: stoped")
        case .playing:
            GLLog?.debug("IJKMPMoviePlayBackStateDidChange: playing")
        case .paused:
            GLLog?.debug("IJKMPMoviePlayBackStateDidChange: paused")
        case .interrupted:
            GLLog?.debug("IJKMPMoviePlayBackStateDidChange: interrupted")
        case .seekingForward,.seekingBackward:
            GLLog?.debug("IJKMPMoviePlayBackStateDidChange: seeking")
        default:
            GLLog?.debug("IJKMPMoviePlayBackStateDidChange: unknow")
        }
    }
    
    // MARK: Install Movie Notifications
    private func installMovieNotificationObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(loadStateDidChange(notification:)), name: NSNotification.Name.IJKMPMoviePlayerLoadStateDidChange, object: player)
        NotificationCenter.default.addObserver(self, selector: #selector(moviePlayBackDidFinish), name: NSNotification.Name.IJKMPMoviePlayerPlaybackDidFinish, object: player)
        NotificationCenter.default.addObserver(self, selector: #selector(mediaIsPreparedToPlayDidChange), name: NSNotification.Name.IJKMPMediaPlaybackIsPreparedToPlayDidChange, object: player)
        NotificationCenter.default.addObserver(self, selector: #selector(moviePlayBackStateDidChange), name: NSNotification.Name.IJKMPMoviePlayerPlaybackStateDidChange, object: player)
    }
    
    // MARK: Remove Movie Notification Handlers
    private func removeMovieNotificationObservers () {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.IJKMPMoviePlayerLoadStateDidChange, object: player)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.IJKMPMoviePlayerPlaybackDidFinish, object: player)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.IJKMPMediaPlaybackIsPreparedToPlayDidChange, object: player)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.IJKMPMoviePlayerPlaybackStateDidChange, object: player)
    }
    
    /*
    private func retry() {
        playErrorView.isHidden = true
        activityIndicator.startAnimating()
        self.destoryPlayer()
        
        let options = IJKFFOptions.byDefault()
        options?.setPlayerOptionIntValue(1, forKey: "videotoolbox")
        options?.setPlayerOptionIntValue(5, forKey: "framedrop")
        let player = IJKFFMoviePlayerController.init(contentURL: URL(string: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")!, with: options)!
        player.scalingMode = .aspectFit
        player.shouldAutoplay = false
        self.addSubview(player.view)
        player.view.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
        gestureActionView.delegatePlayer = player
    }
    */
    
    func play() {
        player.shouldAutoplay = true
        player.prepareToPlay()
        player.play()
    }
    
    func pause() {
        player.pause()
        gestureActionView.updatePlayButtonUI()
    }
    
    func stop() {
        player.stop()
        player.shutdown()
    }
    
    class func gl_image(named name: String) -> UIImage {
        let bundle = Bundle(path: (Bundle(for: self).resourcePath! + "/GLVideoPlayerForIJK.bundle"))
        if let image = UIImage(named: name, in: bundle, compatibleWith: nil) {
            return image
        }
        return UIImage()
    }

    
    deinit {
        GLLog?.debug("deinit GLVideoPlayerView..")
        self.stop()
        self.removeMovieNotificationObservers()
    }
    
}
